package com.ruoyi.common.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.URLUtil;
import com.ruoyi.common.config.MinioConfig;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName MinioUtil
 * @Deacription TODO
 * @Author cmm
 * @Date 2021/6/26 10:18
 * @Version 1.0
 **/

/**
 * @ProjectName: spark-platform
 * @Package: com.spark.platform.file.biz.utils
 * @ClassName: MinioUtil
 * @Author: wangdingfeng
 * @Description: Minio工具类
 * @Date: 2020/11/6 13:19
 * @Version: 1.0
 */
@Component
public class MinioUtil {
    /**
     * 失效时间 7天
     */
    public static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;
    @Autowired
    private MinioConfig minioConfig;
    /**
     * 定义一个单例的MinioClient对象
     */
    @Autowired
    private MinioClient minioClient;

    /**
     * 检查存储桶是否存在
     *
     * @param bucketName 存储桶名称
     * @return
     */
    @SneakyThrows
    public boolean bucketExists(String bucketName) {
        boolean flag = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (flag) {
            return true;
        }
        return false;
    }

    /**
     * 创建存储桶
     *
     * @param bucketName 存储桶名称
     */
    @SneakyThrows
    public boolean makeBucket(String bucketName) {
        boolean flag = bucketExists(bucketName);
        if (!flag) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            return true;
        } else {
            return false;
        }
    }

    /**
     * 列出所有存储桶名称
     *
     * @return
     */
    @SneakyThrows
    public List<String> listBucketNames() {
        List<Bucket> bucketList = listBuckets();
        List<String> bucketListName = new ArrayList<>();
        for (Bucket bucket : bucketList) {
            bucketListName.add(bucket.name());
        }
        return bucketListName;
    }

    /**
     * 列出所有存储桶
     *
     * @return
     */
    @SneakyThrows
    public List<Bucket> listBuckets() {
        return minioClient.listBuckets();
    }

  /*  *//**
     * 删除存储桶
     *
     * @param bucketName 存储桶名称
     * @return
     *//*
    @SneakyThrows
    public boolean removeBucket(String bucketName) {
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                // 有对象文件，则删除失败
                if (item.size() > 0) {
                    return false;
                }
            }
            // 删除存储桶，注意，只有存储桶为空时才能删除成功。
            minioClient.removeBucket(bucketName);
            flag = bucketExists(bucketName);
            if (!flag) {
                return true;
            }

        }
        return false;
    }*/

    /**
     * 列出存储桶中的所有对象名称
     *
     * @param bucketName 存储桶名称
     * @return
     */
    @SneakyThrows
    public List<String> listObjectNames(String bucketName) {
        List<String> listObjectNames = new ArrayList<>();
        boolean flag = bucketExists(bucketName);
        if (flag) {
            Iterable<Result<Item>> myObjects = listObjects(bucketName);
            for (Result<Item> result : myObjects) {
                Item item = result.get();
                listObjectNames.add(item.objectName());
            }
        }
        return listObjectNames;
    }

    /**
     * 列出存储桶中的所有对象
     *
     * @param bucketName 存储桶名称
     * @return
     */
    @SneakyThrows
    public Iterable<Result<Item>> listObjects(String bucketName) {
        return minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 上传本地文件
     *
     * @param bucketName 存储桶
     * @param objectName 对象名称
     * @param fileName 本地文件路径
     *
     */
    @SneakyThrows
    public ObjectWriteResponse putObject(String bucketName, String objectName, String fileName) {
        boolean flag = bucketExists(bucketName);
        ObjectWriteResponse objectWriteResponse=null;
        if (flag) {
             objectWriteResponse= minioClient.uploadObject( UploadObjectArgs.builder().bucket(bucketName).object(objectName).filename(fileName).build());
        }
        return objectWriteResponse;

    }

    /**
     * MultipartFile格式文件上传
     *
     * @param bucketName
     * @param multipartFile
     */
    @SneakyThrows
    public ObjectWriteResponse putObject(String bucketName, MultipartFile multipartFile, String objectName) {
        InputStream inputStream = multipartFile.getInputStream();
        return minioClient.putObject(
                PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(multipartFile.getContentType())
                        .stream(
                                inputStream, inputStream.available(), -1)
                        .build());
    }


    /**
     * 通过InputStream上传对象
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @param stream     要上传的流
     * @param stream     要上传的文件类型 MimeTypeUtils.IMAGE_JPEG_VALUE
     * @return
     */
    @SneakyThrows
    public ObjectWriteResponse putObject(String bucketName, String objectName, InputStream stream) {
        System.out.println(stream.available());

        return minioClient.putObject(
                PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
                        stream, stream.available(), -1).contentType("application/octet-stream")
                        .build());

    }
    /**
     * @Author chenmingming
     * @Description //TODO
     * @Date 20:48 2021/3/4
     * @Param [phone, weixinAvatarUrl]
     * @return com.ruoyi.common.lvlv.api.util.UploadResultEntity
     **/
    public UploadResultEntity uploadWeixinHead(String weixinAvatarUrl) throws IOException {
        URL url1 = URLUtil.url(weixinAvatarUrl);

        InputStream inputStream = url1.openStream();

       // inputStream.read();  //read()为阻塞操作，会等待数据全部返回后执行

        String objectName = MD5Util.MD5(System.currentTimeMillis() + RandomNumberGenerator.generateNumber(8))+".jpg";
        BufferedOutputStream out = FileUtil.getOutputStream(minioConfig.getTempFile()+objectName);
        long copySize = IoUtil.copy(inputStream, out, IoUtil.DEFAULT_BUFFER_SIZE);
        out.close();
        BufferedInputStream in2 = FileUtil.getInputStream(minioConfig.getTempFile()+objectName);
        ObjectWriteResponse objectWriteResponse= putObject( minioConfig.getBucketName(), objectName, in2);
        in2.close();
        FileUtil.del(minioConfig.getTempFile()+objectName);
        UploadResultEntity entity=new UploadResultEntity();
        entity.setAbsoluteURL(minioConfig.getUrl()+"/"+minioConfig.getBucketName()+"/"+objectName);
        return entity;
    }
    /**
     * 以流的形式获取一个文件对象
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @return
     */
    @SneakyThrows
    public InputStream getObject(String bucketName, String objectName) {
        return minioClient
                .getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }
    /**
     * 以流的形式获取一个文件对象（断点下载）
     *
     * @param bucketName 存储桶名称
     * @param objectName 存储桶里的对象名称
     * @param offset     起始字节的位置
     * @param length     要读取的长度 (可选，如果无值则代表读到文件结尾)
     * @return
     */
    @SneakyThrows
    public InputStream getObject(String bucketName, String objectName, long offset, Long length) {
        return minioClient.getObject(
                GetObjectArgs.builder().bucket(bucketName).object(objectName).offset(offset).length(length)
                        .build());
    }
    /**
     * @Author chenmingming
     * @Description //TODO 通用型上传
     * @Date 11:16 2021/6/28
     * @Param [file]
     * @return com.ruoyi.common.utils.UploadResultEntity
     **/
    public UploadResultEntity uploadFile(MultipartFile file) {
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String objectName = MD5Util.MD5(System.currentTimeMillis() + RandomNumberGenerator.generateNumber(8))+suffix;
        ObjectWriteResponse objectWriteResponse= putObject( minioConfig.getBucketName(),file, objectName);
        UploadResultEntity entity=new UploadResultEntity();
        entity.setAbsoluteURL(minioConfig.getDomain()+"/"+minioConfig.getBucketName()+"/"+objectName);
        entity.setFileName(objectName);
        entity.setRelativeURL(minioConfig.getBucketName()+"/"+objectName);
        entity.setUploadId(objectWriteResponse.etag());
        return  entity;
    }
    /**
     * @Author chenmingming
     * @Description //TODO 通用型上传
     * @Date 11:16 2021/6/28
     * @Param [file]
     * @param type 类型 0/null 图片  1是视频 2 apk
     * @return com.ruoyi.common.utils.UploadResultEntity
     **/
    public UploadResultEntity uploadFile(MultipartFile file, Integer type) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, ErrorResponseException, XmlParserException, InternalException {
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String objectName = MD5Util.MD5(System.currentTimeMillis() + RandomNumberGenerator.generateNumber(8))+suffix;
        ObjectWriteResponse objectWriteResponse= putObject( minioConfig.getBucketName(),file, objectName);
        UploadResultEntity entity=new UploadResultEntity();
        String urlPre = type==0?minioConfig.getImage():(type==1?minioConfig.getVideo():minioConfig.getApk());
        entity.setAbsoluteURL(minioConfig.getDomain() + urlPre+"/"+minioConfig.getBucketName()+"/"+objectName);
        entity.setFileName(objectName);
        entity.setRelativeURL(minioConfig.getBucketName()+"/"+objectName);
        entity.setUploadId(objectWriteResponse.etag());
        return  entity;
    }
}
